<?php

use models\Business\Tbk\TbkProduct;
use models\Service\AlibabaproductService;
use Tbk\Tbk as ylTbk;
use Yaf\Registry;
use youliPhpLib\Common\RsaOperation;
use youliPhpLib\Common\Upload;
use youliPhpLib\Common\DirFileOperation;
use youliPhpLib\Common\StringOperation;
use Common\PhpExcelImport;
use Task\client;
use models\Business\SmsCode;
use models\Business\Location;
use models\Business\AlibabaSku;
use models\Business\AlibabaProduct;
use models\Exception\AbstractException;
use models\Business\JPush;
use youliPhpLib\Common\RequestHelper;
use models\Business\Alibaba;
use models\Business\Delivery;
use models\Business\Tbk\Tbk;
use models\Business\Order;
use models\Service\OrderService;
use models\Service\RefundinfoService;
use models\Business\System;
use models\Business\Tbk\TkUrl;
use models\Business\Tbk\TbkOrder;
use models\Business\TencentOauth;
use models\Business\Booking;


class CommonController extends ApiBaseController
{
    /**
     * @SWG\Get(
     *     path="/common/common/rsaEncrypt",
     *     tags={"Common"},
     *     summary="rsa加密",
     *     @SWG\Parameter(
     *          name="sign",
     *          description="要签名的字符串 例username=后台登录账户&password=后台登录密码",
     *          in="query",
     *          required=true,
     *          type="string"
     *     ),
     *     @SWG\Response(
     *          response=200,
     *          description="返回结果中包含error,message,result。result为参数公钥加密过后的字符串"
     *     )
     * )
     */
    public function rsaEncryptAction()
    {
        $rsa = RsaOperation::getInstance(
            Registry::get('config')['rsa']['public_pem'],
            Registry::get('config')['rsa']['private_pem']
        );

        // 签名 后台用的
        $data = $original_str = urldecode(Registry::get("parameters")['sign']);
        parse_str($original_str, $parameter_arr);

        $sign = $rsa->sign($parameter_arr);

        // 加密 给客户端跟前台用的
        $encrypt = $rsa->publicEncrypt($parameter_arr);

        return $this->_responseJson(
            [
                'error' => '000',
                'data' => $parameter_arr,
                'encrypt' => $encrypt,
                'decrypt' => $rsa->privateDecrypt($encrypt),
                'sign_str' => $original_str,
                'sign' => $sign,
                'verify' => $rsa->verify($sign, Registry::get("parameters")['sign'])
            ]
        );
    }

    /**
     *
     * @SWG\Get(
     *     path="/v3/common/jsapi",
     *     tags={"Common"},
     *     description="
     * url 非必须参数 当获取微信分享所需的参数时必须 加密前已经要将url的值进行urlencode",
     *     @SWG\Parameter(
     *          name="Authorization",
     *          description="Authorization 登录接口返回的jwt字段的值",
     *          in="header",
     *          required=true,
     *          type="string"
     *     ),
     *     @SWG\Parameter(
     *          name="secret",
     *          description="所有参数使用&连接的rsa加密结果",
     *          in="query",
     *          required=true,
     *          type="string"
     *     ),
     *     @SWG\Response(
     *          response=200,
     *          description="返回结果中包含error,message,result。result为参数公钥加密过后的字符串"
     *     )
     * )
     */
    public function wechatjsparamAction() {
        $parameters = Registry::get('parameters');
        $original_arr = [];
        if (isset($parameters['url'])) {
            list($original_string, $signature) = TencentOauth::genWeChatJsApiSignature($parameters['url']);
            parse_str($original_string, $original_arr);
            $original_arr['signature'] = $signature;
            $original_arr['app_id'] = TencentOauth::WECHAT_APP_ID;
        }

        if (empty($original_arr))
            throw new \Exception("签名生成失败,参数获取失败", 400);

        return $this->_responseJson(['data' => $original_arr], '000');
    }

    /**
     *
     * @SWG\Get(
     *     path="/v3/common/system",
     *     tags={"Common"},
     *     description="
     * timestamp 必须参数 当前时间戳",
     *     @SWG\Parameter(
     *          name="secret",
     *          description="所有参数使用&连接的rsa加密结果",
     *          in="query",
     *          required=true,
     *          type="string"
     *     ),
     *     @SWG\Response(
     *          response=200,
     *          description="返回结果中包含error,message,result。result为参数公钥加密过后的字符串"
     *     )
     * )
     */
    public function systemAction() {
        $parameters = Registry::get('parameters');

        $system = System::getSystemInfo(1);


        $return_arr = [
            'title' => $system['title'] . $system['title_suffix'],
            'keywords'=>$system['keywords'],
            'description'=>$system['description'],
            'download' => Registry::get('iPhone') === true ? $system['download_iOS'] : $system['download_Android'],
            'about_us' => $system['about_us'],
            'coupon_protocol' => $system['coupon_protocol'],
            'refund_protocol' => $system['refund_protocol'],
            'return_protocol' => $system['return_protocol'],
            'customer_service' => $system['customer_service'],
            'customer_qq' => $system['customer_qq'],
            'customer_wechat' => $system['customer_wechat'],
            'advance' => $system['advance'],
            'help' => $system['help'],
            'record' => $system['record'],
            'order' => $system['order_info'],
            'tbkDetailUrl' => 'https://mdetail.tmall.com/templates/pages/desc?id=',
            'registration_agreement' => $system['registration_agreement'],
            'cmc_terms_agreement' => $system['cmc_terms_agreement'],
            'coupon_introduction' => $system['coupon_introduction'],
            'integral_introduction' => $system['integral_introduction'],
            'legal_notice' => $system['legal_notice'],
            'privacy_agreement' => $system['privacy_agreement'],
            'alibabaDetailUrl' => 'http://douziyoupin.com/product?gtype=tuan&id=',
            'alibabaTDetailUrl' => 'http://douziyoupin.com/product?id=',
            'invitation'=>'http://douziyoupin.com/invitation?invite_code=',
            'video'=>'http://online.animiz.cn/gczlh/dhmk/video.mp4',
        ];

        return $this->_responseJson(['data' => $return_arr]);
    }

    /**
     *
     * @SWG\Get(
     *     path="/v3/common/settings",
     *     tags={"Common"},
     *     description="
     * timestamp 必须参数 当前时间戳",
     *     @SWG\Parameter(
     *          name="secret",
     *          description="所有参数使用&连接的rsa加密结果",
     *          in="query",
     *          required=true,
     *          type="string"
     *     ),
     *     @SWG\Response(
     *         response="200",
     *         description="请求成功",
     *         @SWG\Schema(type="object", ref="#/definitions/settingsSingleData")
     *     ),
     * )
     */
    public function settingsAction() {
        $parameters = Registry::get('parameters');

        $system = System::getSettingsInfo(1);


        $return_arr = [
            'coupon_in_hot_title' => $system['coupon_in_hot_title'],
            'coupon_list_title' => $system['coupon_list_title'],
            'coupon_intro_in_details' => $system['coupon_intro_in_details'],
            'coupon_rebate_in_details' => $system['coupon_rebate_in_details'],
            'coupon_wait_for_coupon_list' => $system['coupon_wait_for_coupon_list'],
            'coupon_wait_for_coupon_title' => $system['coupon_wait_for_coupon_title'],
            'coupon_button' => $system['coupon_button']
        ];

        return $this->_responseJson(['data' => $return_arr]);
    }

    /**
     *
     * @SWG\Get(
     *     path="/v3/common/booking",
     *     tags={"Common"},
     *     description="
     * 这个接口的目的只是为了展示order/list在stats=0或stats=10的情况下，order/list返回结果的结构",
     *     @SWG\Parameter(
     *          name="secret",
     *          description="所有参数使用&连接的rsa加密结果",
     *          in="query",
     *          required=true,
     *          type="string"
     *     ),
     *     @SWG\Response(
     *         response="200",
     *         description="请求成功",
     *         @SWG\Schema(type="object", ref="#/definitions/bookingListData")
     *     )
     * )
     */
    public function bookingAction() {

    }

    public function removeAction() {
        $parameters = Registry::get('parameters');

        if ($parameters['type'] == 'sku') {
            AlibabaSku::deleteSkuImage($parameters);
            return $this->_responseJson(new stdClass(), '000', '删除成功');
        } else if (in_array($parameters['type'], ['category_icon', 'product_main_image', 'product_main_video', 'product_images', 'ad_image', 'exchange_icon'])) {
            AlibabaProduct::deleteMainImageVideo($parameters);
            return $this->_responseJson(new stdClass(), '000', '删除成功');
        }

        return $this->_responseJson([$parameters['type'] == 'sku', $parameters]);
    }

    /**
     * @SWG\Post(
     *     path="/common/common/upload",
     *     tags={"Common"},
     *     summary="上传图片",
     *     description="测试上传图片地址:http://192.168.x.x:xxx/index/test",
     *     consumes={"multipart/form-data", "application/x-www-form-urlencoded"},
     *     @SWG\Parameter(
     *          name="file",
     *          description="图片",
     *          in="formData",
     *          required=true,
     *          type="file"
     *     ),
     *     @SWG\Response(
     *          response=200,
     *          description="返回结果中包含error,message,result。result为参数公钥加密过后的字符串"
     *     )
     * )
     */
    public function uploadAction() {
        $response['file'] = 'error';
        $bucket = Registry::get('parameters')['type'];
        $table_name = Registry::get('parameters')['table_name'];
        $request_file = Registry::get('parameters')['file'];

        if ($request_file) {
            $target_dir = APP_PATH . Registry::get("config")['upload']['target_dir'] . '/' . $bucket . '/';
            $file_path = $target_dir . basename($request_file['name']);
            $dir_file_operation = new DirFileOperation($file_path);
            $make_dir_result = $dir_file_operation->chkFileDir();
            if ($make_dir_result !== true) {
                $e = new Exception(str_replace('%s', $request_file['name'], AbstractException::UPLOAD_MAKE_DIR_FAILED . '(' . $make_dir_result . ')'), '003');
                throw $e;
            }
            $upload = new Upload($request_file);
            $result = $upload->setAllowedTypes(Registry::get("config")["upload"]["file_extension"])
                ->setMaxWidth(Registry::get("config")['upload']['thumb']['max_width'])
                ->setMaxHeight(Registry::get("config")["upload"]['thumb']["max_height"])
                ->setMaxSize(Registry::get("config")["upload"]['thumb']["max_size"])
                ->setDestination($target_dir)
                ->upload();

            if (is_string($result)) {
                $res = str_replace(APP_PATH . '/' . 'public', '', $result);

                // 若上传的是证书
                if ($request_file['type'] == 'application/x-x509-ca-cert') {
                    $ip = isset(Registry::get('parameters')['ip']) ? Registry::get('parameters')['ip'] : '';
                    if (empty($ip))
                        throw new Exception('ip白名单不能为空', '400');

                    $new_file_path = substr($res, 0, strrpos($res, '/') + 1) . $ip . '.' . pathinfo(basename($request_file['name']), PATHINFO_EXTENSION);

                    if (! copy(APP_PATH . '/public' . $res, APP_PATH . '/public' . $new_file_path))
                        throw new Exception('证书复制失败', '400');
                    if (! unlink(APP_PATH . '/public' . $res))
                        throw new Exception('文件删除失败', '400');
                    $res = $new_file_path;
                }

                $response['file'] = Registry::get('config')['application']['host'] . $res;

                // sku图片上传时直接修改sku
                if ($bucket === 'sku')
                    AlibabaSku::editSkuImage(['sku_id' => Registry::get('parameters')['skuId'],
                        'product_id' => Registry::get('parameters')['productId'], 'file' => $res]);

                // 导入的excel 批量插入
                $file_type = pathinfo($res, PATHINFO_EXTENSION);
                if (!empty($table_name) && ($file_type == 'xlsx' || $file_type == 'xls') ) {
                    $table_name = 'products';
                    PhpExcelImport::getInstance($table_name)->setFileName(APP_PATH . '/public/' . $res)
                        ->import();
                }
            }
        }
        return $this->_responseJson(['data' => $response]);
    }

    /**
     * 发送短信验证码接口 不对外开放
     * @return bool
     * @throws \models\Exception\Business\CodeException
     */
    public function msgAction() {
        Registry::get('sms_log')->info('msg action parameters: ' . json_encode(Registry::get('parameters')));

        $result = SmsCode::sendMessage(Registry::get('parameters')['mobile'], Registry::get('parameters')['content']);

        Registry::get('sms_log')->info('msg action result: ' . $result);

        return $this->_responseJson(['success']);
    }

    /**
     * @SWG\Get(
     *     path="/v3/common/verification",
     *     tags={"Common"},
     *     summary="获取短信验证码",
     *     description="
     * mobile 必须参数 手机号码
     * type 必须参数 类型 可选值: login=登陆,register=注册,修改、忘记密码=resetpassword,第三方登陆账号绑定手机号=bindmobile,
     *     绑定提现所需支付宝=bindalipay,修改绑定提现所需的支付宝账号=modifyalipay,支付密码设置、修改=paypassword,忘记密码=forgetPwd,
     * captcha=图片验证码 非必须参数",
     *     @SWG\Parameter(
     *          name="secret",
     *          description="所有参数使用&连接的rsa加密结果",
     *          in="query",
     *          required=true,
     *          type="string"
     *     ),
     *     @SWG\Response(
     *          response=200,
     *          description="返回结果中包含error,message,result。result为参数公钥加密过后的字符串"
     *     )
     * )
     */
    public function verificationAction() {
        $verification_result = true;

        //校验图片验证码
        if (isset(Registry::get("parameters")["captcha"])) {
            $verification_result = \Common\Verification::checkVerification(
                Registry::get("parameters")["mobile"],
                Registry::get("parameters")["type"],
                Registry::get("parameters")["captcha"],
                true
            );
        }

        if ($verification_result !== true) throw new Exception("图片验证码校验失败");

        //验证手机号码有效性
        try {
            StringOperation::mobileIsValid(Registry::get("parameters")["mobile"]);
        } catch (Exception $e) {
            throw new Exception($e->getMessage(), 400);
        }

        //获取短信验证码
        $verification_arr = SmsCode::genSmsCode(
            Registry::get('parameters')['mobile'],
            Registry::get('parameters')['type']
        );

        //生成发送短信验证码的参数，调用接口，发送短信验证码
        if (Registry::get('parameters')['type'] == 'alipay')
            $content = SmsCode::ALIPAY_BIND_TEMPLATE;
        else
            $content = SmsCode::REGISTER_SMS_TEMPLATE;
        $content = str_replace("#verification#", $verification_arr['verification'], $content);

//        return $this->_responseJson($content);

        $client = new client();
        try {
            $client->connect();
            $client->sendMsg($content, Registry::get('parameters')['mobile']);
        } catch (Exception $e) {
            Registry::get('sms_log')->err($e->getMessage());
        } finally {
            $client->close();
        }

        return $this->_responseJson(['data' => [Registry::get('parameters')['mobile'], $verification_arr['verification']]]);
    }

    /**
     * @SWG\Get(
     *     path="/v3/common/location",
     *     tags={"Common"},
     *     summary="获取省市区县街道接口",
     *     description="
     * type 必须参数 类型 可选值: 1为省份，2为城市，3为区县，4为街道
     * parent_id 非必须参数 上级行政单位编号 获取市、区县、街道时必须，需要发送上级行政单位编号",
     *     @SWG\Parameter(
     *          name="secret",
     *          description="所有参数使用&连接的rsa加密结果",
     *          in="query",
     *          required=true,
     *          type="string"
     *     ),
     *     @SWG\Response(
     *          response=200,
     *          description="返回结果中包含error,message,result。result为参数公钥加密过后的字符串"
     *     )
     * )
     */
    public function locationAction() {
        $parameters = Registry::get('parameters');

        $data = Location::getLocation(
            isset($parameters['parent_id']) ? $parameters['parent_id'] : '', $parameters['type']);

        return $this->_responseJson(['data' => $data]);
    }

    /**
     * 暂不对外开放
     * 根据订单编号推送消息给订单所属会员
     */
    public function orderPushAction() {
        $parameters = Registry::get('parameters');

        $res = JPush::orderPush($parameters['sn']);

        return $this->_responseJson($res);
    }

    /**
     * 暂不对外开放
     * 根据订单编号推送消息给参与拼团的所有会员
     */
    public function couponPushAction() {
        $parameters = Registry::get('parameters');

        JPush::couponResultPush($parameters['sn']);

        return $this->_responseJson('done');
    }

    /**
     * 暂不对外开放
     * 根据产品编号与购买数量，从拼团队列中获取距离现在时间最久的n个(0<n<=2)拼团信息出来计算拼团结果
     */
    public function couponResultAction() {
        $parameters = Registry::get('parameters');
        Registry::get('transformer_log')->info(__METHOD__ . 'time: ' . time() . ', parameters: ' . json_encode($parameters));

        $redis = Registry::get('redis');
        $redis->select(3);

        $key = 'product:paid:' . $parameters['product_id'] /*. ':' . $parameters['num']*/;
        $len = $redis->llen($key);
        Registry::get('coupon_log')->info('阿里巴巴下单, ' . $key . '数据长度: ' . $len);
        // 队列为空
        if ($len == 0)
            throw new Exception('队列空',  400);

        $redis->watch($key);
        // 开启pipeline
        $redis->pipeline();

        $redis->lPop($key);
        $redis->lPop($key);

        $redis->unwatch();
        $res = $redis->exec();

        Registry::get('coupon_log')->info('结果: ' . json_encode($res));
        list($element_1, $element_2, $pop_res) = $res;
        Registry::get('coupon_log')->info('拼单数据1: ' . json_encode($element_1));
        Registry::get('coupon_log')->info('拼单数据2: ' . json_encode($element_2));
        Registry::get('coupon_log')->info('队列取值结果: ' . json_encode($pop_res));
        $data = [];
        if ($element_1 !== false && null !== $booking_arr_1 = json_decode($element_1, true))
            array_push($data, $booking_arr_1['sn']);

        if ($element_2 !== false && null !== $booking_arr_2 = json_decode($element_2, true))
            array_push($data, $booking_arr_2['sn']);

        if (empty($data))
            throw new Exception("booking数据有误", 400);

        Registry::get('coupon_log')->info('阿里巴巴下单加密前的参数: ' . json_encode($data));
        $data = [
            'secret' => RsaOperation::getInstance()->publicEncrypt(['sn' => implode(',', $data)])
        ];
//        $header = ['Content-type: '];
        $url = Registry::get('config')['application']['host'] . '/v3/order/order2Alibaba';
        Registry::get('coupon_log')->info('阿里巴巴下单.url : ' . $url . '. data: ' . json_encode($data));
        list($header_size, $body) = RequestHelper::curlRequest($url,  http_build_query($data), 'POST');
        Registry::get('coupon_log')->info('阿里巴巴下单结果: ' . $header_size . ', ' . $body);
        $resp = json_decode($body, true);

        return $this->_responseJson($resp);
    }

    /**
     * 暂不对外开放
     * 从1688接口读取常用的几家物流公司的信息，并写入到redis中
     */
    public function logisticsAction() {
        // 以下两个接口具体用哪个暂时也不清楚，等申请接口的时候再找小二问清楚
        // 获取所有的物流公司名称
        $logistic_company_list = Alibaba::getLogisticsOpQueryLogisticCompanyList();
        // 查询自己联系物流的物流公司列表
        //$logistic_company_list = Alibaba::getLogisticsOpQueryLogisticCompanyListOffline();

        $arr = [];
        foreach ($logistic_company_list as $val) {
            if (in_array($val['companyName'], ['韵达', '顺丰', '申通', '圆通', 'EMS', '中通', '百世快运'])) {
                array_push($arr, [
                    'id' => $val['id'],
                    'company_name' => $val['companyName'],
                    'company_no' => $val['companyNo'],
                    'company_phone' => $val['companyPhone'],
                    'support_print' => $val['supportPrint'] === true ? 1 : 0,
                ]);
            }
        }

        if (!empty($arr))
            Delivery::collectDelivery($arr);
    }

    /**
     * 命令行启动异步任务实现的定时采集任务
     * @return bool
     * @throws Exception
     */
    public function launchCollectAction() {
        if($this->getRequest()->isCli() !== true) {
            throw new Exception('非法请求');
        }

        $client = new client();
        try {
            $client->connect();
            $client->getTbkProduct();
        } catch (Exception $e) {
            echo $e->getMessage();
        } finally {
            $client->close();
        }

        return $this->_responseString('success');
    }

    /**
     * 暂不对外开放
     * 采集好单库商品
     * @return bool
     * @throws Exception
     */
    public function getTbkProductByTimingAction() {
        Registry::get('tbk_log')->info('---------------采集开始---------------');

        try {
            $res = Tbk::getProductByTiming();
            if ($res !== true)
                throw new Exception('采集失败', 400);
        } catch (Exception $e) {
            throw $e;
        }

        return $this->_responseString('success');
    }

    public function getTbkProductIntoDbAction() {
        Registry::get('tbk_log')->info('---------------入库开始---------------');
        $parameters = Registry::get('parameters');
        Registry::get('tbk_log')->info('待入库商品数据: ' . json_encode($parameters));

        try {
            TbkProduct::collectTbkProduct([$parameters]);
        } catch (Exception $e) {
            throw $e;
        }

        return $this->_responseString('success');
    }

    public function refundReturn2AlibabaAction() {

    }

    /**
     * 命令行启动 调用1688的退货退款申请接口
     * @throws Exception
     */
    public function refundReturnAction() {
        try {
            if($this->getRequest()->isCli() !== true)
                throw new Exception('该接口只允许cli调用', 400);

            $start_datetime = date('Y-m-d H:i:s', time() - 3600 * 7);
            $end_datetime = date('Y-m-d H:i:s', time() - 3600 * 6);
            $refund_list = RefundinfoService::getInstance()->getList(1, 999999, 'asc', 'created_at',
                ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'refund_order_id', 'op' => 'eq', 'data' => '0'],
                    ['field' => 'created_at', 'op' => 'ge', 'data' => $start_datetime],
                    ['field' => 'created_at', 'op' => 'le', 'data' => $end_datetime]
                ]]);

            if (empty($refund_list['data']))
                throw new Exception($start_datetime . "到" . $end_datetime . "之间没有退货、退款订单");

            // 查询凭证信息
            $album_id_arr = array_column($refund_list['data'], 'album_id');
            $album_list = \models\Service\AlbumsService::getInstance()->getList(1, 999999, 'asc', 'id',
                ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'id', 'op' => 'in', 'data' => implode(',', $album_id_arr)]]]);
            $album_arr = [];
            foreach ($album_list['data'] as $idx => $album_info) {
                $album_arr[$album_info['id']] = !is_null(unserialize($album_info['album'])) ?
                    APP_PATH . implode(',' . APP_PATH, unserialize($album_info['album'])) : '';
            }

            // 查询订单信息
            $order_sn_arr = array_column($refund_list['data'], 'order_sn');
            $order_list = OrderService::getInstance()->getList(1, count($order_sn_arr), 'asc', 'created_at',
                ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'stats', 'op' => 'in', 'data' => '1,2'],
                    ['field' => 'refund_stats', 'op' => 'in', 'data' => '1,2'],
                    ['field' => 'sn', 'op' => 'in', 'data' => implode(',', $order_sn_arr)]
                ]]);
            $order_sn_arr = array_column($order_list['data'], 'sn');

            $client = new client();
            foreach ($refund_list['data'] as $idx => $refund_info) {
                if (false !== $key = array_search($refund_info['order_sn'], $order_sn_arr)) {
                    $refund_info['album'] = isset($album_arr[$refund_info['album_id']]) ?
                        $album_arr[$refund_info['album_id']]: '';

                    // 异步任务
                    try {
                        $client->connect();
                        $client->alibabaRefundReturn($refund_info, $order_list['data'][$key]);
                    } catch (Exception $e) {
                        Registry::get('crontab_log')->info("异步调用1688退款退货接口失败{$e->getMessage()}");
                    } finally {
                        $client->close();
                    }

                    // 同步执行
                    // 记录调用refundReturn的入参
//                    Registry::get('crontab_log')->info("订单编号(" . $refund_info['order_sn'] . ")调用1688退款退货接口参数: " . json_encode([
//                            'parameters' => $refund_info, 'orders' => $order_list['data'][$key]]));
                    // 调用1688退货退款接口
//                    $msg = Order::refundReturn($refund_info, $order_list['data'][$key]);
                    // 记录refundReturn的结果
//                    Registry::get('crontab_log')->info("订单编号(" . $refund_info['order_sn'] . ")调用1688退款退货接口结果: " . $msg);

                } else
                    Registry::get('crontab_log')->err("订单编号(" . $refund_info['order_sn'] . ")没有匹配的order表的记录");
            }

        } catch (Exception $e) {
            Registry::get('crontab_log')->err("定时任务处理退货退款订单报错: {$e->getMessage()}");
            throw $e;
        }
    }

    /**
     * 命令行启动 每1小时执行一次
     * 批量修改商品的浏览量
     */
    public function updateClicksAction() {
        if($this->getRequest()->isCli() !== true)
            throw new Exception('该接口只允许cli调用', 400);

        $redis = Registry::get('redis');
        try {
            $redis->ping();
        } catch (\Exception $e) {
            $redis->auth(Registry::get('config')['redis']['master']['auth']);
        }

        try {
            $redis->select(7);
            $keys_arr = $redis->keys("alibaba_product_clicks:*");
            $data = [];
            foreach ($keys_arr as $key) {
                $key_arr = explode(':', $key);
                $product_id = $key_arr[count($key_arr) - 1];
                // 生成商品编号 => 点击量的数组
                $data[$product_id] = $redis->get($key);
            }

            if (empty($data))
                throw new Exception("没有点击量", 400);

            // 查询商品旧的点击量
            $clicks = AlibabaproductService::getInstance()->getList(1, count($data), 'desc', 'product_id',
                ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'product_id', 'op' => 'in', 'data' => implode(',', array_keys($data))]]]);
            if (empty($clicks['data']))
                throw new Exception("商品不存在", 400);
            $product_id_old_click = array_column($clicks['data'], 'clicks', 'product_id');

            // 删除点击量缓存，生成批量修改数据库的数组
            $redis->pipeline();
            $batch_update_arr = [];
            foreach ($data as $product_id => $clicks) {
                if (isset($product_id_old_click[$product_id])) {
                    array_push($batch_update_arr, ['product_id' => $product_id,
                        'clicks' => $clicks + $product_id_old_click[$product_id]]);
                    $redis->del('alibaba_product_clicks:' . $product_id);
                }
            }
            $redis->exec();

            // 批量修改数据库数组存在
            if (!empty($batch_update_arr))
                AlibabaproductService::getInstance()->batchUpdate($batch_update_arr);

            return $this->_responseString('success');
        } catch (Exception $e) {
            Registry::get('crontab_log')->err(__METHOD__ . '定时更新点击量出错。' . $e->getMessage());
        }
    }

    /**
     * 命令行启动 每1小时执行一次
     * 批量修改商品浏览量
     */
    public function updateViewsAction() {
        if($this->getRequest()->isCli() !== true)
            throw new Exception('该接口只允许cli调用', 400);

        $redis = Registry::get('redis');
        try {
            $redis->ping();
        } catch (\Exception $e) {
            $redis->auth(Registry::get('config')['redis']['master']['auth']);
        }

        try {
            $redis->select(7);
            $keys_arr = $redis->keys("alibaba_product_views:*");
            $data = [];
            foreach ($keys_arr as $key) {
                $key_arr = explode(':', $key);
                $product_id = $key_arr[count($key_arr) - 1];
                // 生成商品编号 => 浏览量的数组
                $data[$product_id] = $redis->get($key);
            }

            if (empty($data))
                throw new Exception("没有浏览记录", 400);

            // 查询商品旧的浏览量
            $views_arr = AlibabaproductService::getInstance()->getList(1, count($data), 'desc', 'product_id',
                ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'product_id', 'op' => 'in', 'data' => implode(',', array_keys($data))]]]);
            if (empty($views_arr['data']))
                throw new Exception("商品不存在", 400);
            $product_id_old_views = array_column($views_arr['data'], 'views', 'product_id');

            // 删除浏览量缓存，生成批量修改数据库的数组
            $redis->pipeline();
            $batch_update_arr = [];
            foreach ($data as $product_id => $views) {
                if (isset($product_id_old_views[$product_id])) {
                    array_push($batch_update_arr, ['product_id' => $product_id,
                        'views' => $views + $product_id_old_views[$product_id]]);
                    $redis->del('alibaba_product_views:' . $product_id);
                }
            }
            $redis->exec();

            // 批量修改数据库数组存在
            if (!empty($batch_update_arr))
                AlibabaproductService::getInstance()->batchUpdate($batch_update_arr);

            return $this->_responseString('success');
        } catch (Exception $e) {
            Registry::get('crontab_log')->err(__METHOD__ . '定时更新浏览量出错。' . $e->getMessage());
        }
    }

    /**
     * 每6个钟头执行一次
     * 将数据库中所有未结算的订单全部拿去调用一次接口，看看订单是否结算了
     */
    public function getUnSettledTbkOrderAction() {
        Registry::get('crontab_log')->info(__METHOD__);
        $tbk_orders = TbkOrder::getOrderList([
            'stats' => 2, 'page' => 1, 'page_size' => 9999]);

        foreach ($tbk_orders['data'] as $tbk_order) {
            $param = [
                'start_time' => $tbk_order['create_time'],
                'end_time' => date('Y-m-d H:i:s', strtotime($tbk_order['create_time']) + 60),
                'page_no' => 1,
                'page_size' => 1,
                'query_type' => 1
            ];
            Registry::get('crontab_log')->info('查询接口的参数:' . json_encode($param));
            list($position_index, $order_arr, $has_next) = TkUrl::getOrderList($param);

            if (!empty($order_arr)) {

                // 订单已结算
                if (in_array($order_arr[0]['order_stats'], [1, 4])) {
                    Registry::get('crontab_log')->info('开始修改数据库。订单编号为: ' . $order_arr[0]['order_sn'] . '。订单状态为:' . $order_arr[0]['order_stats']);
                    TbkOrder::collectTbkOrder($order_arr);
                } else {
                    Registry::get('crontab_log')->info('结果: 订单编号为: ' . $order_arr[0]['order_sn'] . '的订单状态不需要修改订单状态(' . $order_arr[0]['order_stats'] . ')');
                }
            } else
                Registry::get('crontab_log')->info('结果: 订单编号为: ' . $tbk_order['order_sn'] . '的订单查无结果');
        }

        return $this->_responseString('success');
    }

    /**
     * 命令行启动 每一分钟执行一次
     * 获取对应状态的淘客订单
     * tk_status: 3已结算、12已付款、13关闭
     */
    public function getTbkOrderAction() {
        if($this->getRequest()->isCli() !== true)
            throw new Exception('该接口只允许cli调用', 400);
        $parameters = $this->getRequest()->getParams();
        $tk_status = isset($parameters['tk_status']) ? $parameters['tk_status'] : 12;
        Registry::get('crontab_log')->info('定时采集淘宝已支付订单:' . json_encode($parameters));

        $has_next = true;
        $order_array = [];
        $page = 1;
        $page_size = 20;
        while ($has_next === true) {
            $param = [
                // huangxu4328的已付款
//                'start_time' => '2020-06-06 10:50:00',
//                'end_time' => '2020-06-06 11:00:00',
                // 厦门宥理79712的已结算
                'start_time' => '2020-07-18 16:10:00',
                'end_time' => '2020-07-18 16:15:00',
//                'start_time' => date('Y-m-d H:i:00', time() - 60),
//                'end_time' => date('Y-m-d H:i:00', time()),
                'page_no' => $page,
                'page_size' => $page_size,
                'tk_status' => $tk_status
            ];

            list($position_index, $order_arr, $has_next) = TkUrl::getOrderList($param);
            if (!empty($order_arr))
                $order_array = array_merge($order_array, $order_arr);
            if ($has_next === true)
                $page += 1;
        }

        if (!empty($order_array)) {

            TbkOrder::collectTbkOrder($order_array);

            foreach ($order_array as $order_info) {
                $member_id = \models\Business\Tbk\TbkSdk\Tbk::getTbkOrderMemberIdBySn($parameters['sn']);
                if (!empty($member_id))
                    TbkOrder::rebate($parameters['sn'], $member_id);
//                $client = new client();
//                $client->connect();
//                $client->getTbkOwnerByOrderSn($order_info['order_sn']);
//                $client->close();
            }
        }

        exit('done');
    }

    public function getOwnerByOrderSnAction() {
        $parameters = Registry::get('parameters');

        Registry::get('tbk_log')->info(__METHOD__ . ' - ' . json_encode($this->getRequest()->getParams()));

        $member_id = \models\Business\Tbk\TbkSdk\Tbk::getTbkOrderMemberIdBySn($parameters['sn']);

        Registry::get('tbk_log')->info(__METHOD__ . ' - ' . $member_id);

        if (!empty($member_id))
            TbkOrder::rebate($parameters['sn'], $member_id);

        return $this->_responseString('success');
    }

    /**
     * 命令行启动 每天定时计算30天销量
     */
    public function get30daysSalesStatisticsAction() {
        try {
            if($this->getRequest()->isCli() !== true)
                throw new Exception('该接口只允许cli调用', 400);

            $start_date = date('Y-m-d', strtotime("-30 day"));
            $end_date = date("Y-m-d", time());

            // 查询订单信息
            $model = \models\DAO\OrderModel::getInstance();
            $conn = $model->getConn();
            $sql = "SELECT count(`sn`) AS total, `product_id` FROM `order` WHERE `type` = 0 AND `refund_stats` = 0 AND `stats` = 3 AND ".
                "`created_at` BETWEEN '$start_date' AND '$end_date' GROUP BY `product_id`";
            $order = $model->query($sql);

            if (empty($order)) {
                throw new Exception("订单不存在");
            }

            $sql_arr = $match_arr = [];
            foreach ($order as $order_info) {
                array_push($sql_arr, ['product_id' => $order_info['product_id'],
                    'sales_in_30_days' => $order_info['total']]);
            }

            if (!empty($sql_arr))
                AlibabaproductService::getInstance()->batchUpdate($sql_arr);

            return $this->_responseString('success');
        } catch (Exception $e) {
            Registry::get('crontab_log')->err(__METHOD__ . '定时更新浏览量出错。' . $e->getMessage());
        }
    }

    public function confirmAlibabaOrderAction() {
        $start_datetime = date('Y-m-d H:i:s', time() - 86400 * 7);
        $end_datetime = date('Y-m-d H:i:s', time() - 86400 * 6);
        $order_list = OrderService::getInstance()->getList(1, 999999, 'asc', 'created_at',
            ['groupOp' => 'AND', 'rules' => [
                ['field' => 'stats', 'op' => 'eq', 'data' => '2'],
                ['field' => 'refund_stats', 'op' => 'eq', 'data' => '0'],
                ['field' => 'trade_order_sn', 'op' => 'ne', 'data' => '0'],
//                ['field' => 'created_at', 'op' => 'ge', 'data' => $start_datetime],
//                ['field' => 'created_at', 'op' => 'le', 'data' => $end_datetime]
            ]]);

        if (empty($order_list['data']))
            throw new Exception($start_datetime . "到" . $end_datetime . "之间没有需要确认收货的订单");

        $client = new client();
        foreach ($order_list['data'] as $order_info) {
            try {
                $client->connect();
                $client->getDeliveryInfoBySn($order_info['trade_order_sn']);
            } catch (Exception $e) {

            } finally {
                $client->close();
            }
        }

        exit('done');
    }

    /**
     * 不对外开放 操你个1688采集数据库中stats=0的商品
     */
    public function reacquireProductAction() {
        $product_list = AlibabaProduct::getProductList(['page' => 1, 'page_size' => 999, 'sort' => 'desc', 'order' => 'product_id', 'stats' => 0]);
        $product_id_arr = array_column($product_list['data'], 'product_id');

        if (!empty($product_id_arr)) {

            $client = new client();
            foreach ($product_id_arr as $product_id) {
                try {
                    $client->connect();
                    $client->productCpsMediaProductInfo($product_id);
                } catch (Exception $e) {
                    Registry::get('alibaba_log')->err(__METHOD__ . ' error: ' . $e->getMessage());
                } finally {
                    $client->close();
                }
            }
        } else
            return $this->_responseString('error');

        return $this->_responseString('success');
    }

    public function cleanTimeoutCouponAction() {
        if ($this->getRequest()->isCli() !== true)
            throw new Exception('该接口只允许cli调用', 400);

        $redis = Registry::get('redis');
        try {
            $redis->ping();
        } catch (\Exception $e) {
            $redis->auth(Registry::get('config')['redis']['master']['auth']);
        }

        try {
            $redis->select(3);
            $keys_arr = $redis->keys("product:wait4pay:*");
            Registry::get('crontab_log')->info(__METHOD__ . '待检查的等待支付的拼单数据的key。' . json_encode($keys_arr));
            $data = [];
            foreach ($keys_arr as $key) {
                $key_arr = explode(':', $key);
                $product_id = $key_arr[count($key_arr) - 1];
                // 生成商品编号 => 点击量的数组
                $list = $redis->zRange($key, 0, -1, true);
                foreach ($list as $val => $score) {
                    $coupon_arr = json_decode($val, true);
                    $data[$key] = isset($data[$key]) && !empty($data[$key]) ? $data[$key] : [];
                    if ($coupon_arr['expired_at'] < date('Y-m-d H:i:s', time())) {
                        array_push($data[$key], $val);
                    }
                }
            }

            Registry::get('crontab_log')->info(__METHOD__ . '待删除的等待支付的拼单数据。' . json_encode($data));
            if (empty($data))
                throw new Exception("没有等待用户支付的拼单数据", 400);

            // 删除点击量缓存，生成批量修改数据库的数组
            $redis->pipeline();
            $batch_update_arr = [];
            foreach ($data as $key => $val_arr) {
                foreach ($val_arr as $val)
                    $redis->zRem($key, $val);
            }
            $res = $redis->exec();
            Registry::get('crontab_log')->info(__METHOD__ . '删除结果。' . json_encode($res));

            return $this->_responseString('success');
        } catch (Exception $e) {
            Registry::get('crontab_log')->err(__METHOD__ . '定时清楚待支付的拼单数据出错。' . $e->getMessage());
        }
    }

    /**
     * 不对外开放 支付或退款
     * @return bool
     * @throws Exception
     */
    public function delay2PayOrRefundAction() {
        $parameters = Registry::get('parameters');
        Registry::get('transformer_log')->info(__METHOD__ . 'time: ' . time() . ', parameters: ' . json_encode($parameters));

        try {
            Order::payOrRefund($parameters['trade_order_sn'], $parameters['action'], $parameters['platform']);
            return $this->_responseString('success');
        } catch (Exception $e) {
            Registry::get('crontab_log')->err(__METHOD__ . '延迟下单报错。' . $e->getMessage());
        }
    }

    /**
     * 不对外开放 重复发起机器拼团订单
     * @return bool
     * @throws Exception
     */
    public function updateJqBookingAction() {
        $parameters = Registry::get('parameters');
        Registry::get('coupon_log')->info(__METHOD__ . 'time: ' . time() . ', parameters: ' . json_encode($parameters));
        try {
            Booking::handlerMachineBookingByProductId($parameters['product_id']);
            return $this->_responseString('success');
        } catch (Exception $e) {
            Registry::get('crontab_log')->err(__METHOD__ . '重复发起拼单报错。' . $e->getMessage());
        }
    }
}
